package com.supermarket.manage.business.stocking.controller;

import com.alibaba.fastjson.JSON;
import com.supermarket.manage.common.constant.RedisKeyConstant;
import com.supermarket.manage.common.constant.StockConstant;
import com.supermarket.manage.common.dto.CodeStatus;
import com.supermarket.manage.common.dto.PageBean;
import com.supermarket.manage.common.dto.ResponseResult;
import com.supermarket.manage.common.dto.prod.request.ProdPageParams;
import com.supermarket.manage.common.dto.prod.response.ProductDto;
import com.supermarket.manage.common.dto.stock.request.StockProdParams;
import com.supermarket.manage.common.dto.stock.response.StockProdDto;
import com.supermarket.manage.common.utils.BigDecimalUtil;
import com.supermarket.manage.common.validation.CheckGroup;
import com.supermarket.manage.provider.api.product.ProductService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author Faxon
 * @version 1.0
 * @date 2020-03-17 16:04
 **/
@RestController
@RequestMapping("/stocking")
@Api(value = "StockingProdController", tags = "盘点商品管理接口")
public class StockingProdController {

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Reference(version = "1.0.0")
    private ProductService productService;

    @PreAuthorize("hasAnyAuthority('/','/stocking/get')")
    @PostMapping("/getAllProd")
    @ApiOperation(value = "获取商品分页列表", notes = "必传参数：新增单据时status为0，传递当前登录用户userId;编辑单据时status为1，传递本单据id；page，size，buyerId，（pname，cid为商品搜索条件），其他字段均与此接口无关")
    public ResponseResult<PageBean<StockProdDto>> getAllProd(@Validated({CheckGroup.Page.class, CheckGroup.Get.class})
                                                             @RequestBody StockProdParams<StockProdDto> params) {
        String redisKey = getRedisKey(params);
        if (redisKey.startsWith("参数错误")) {
            return new ResponseResult<>(CodeStatus.ILLEGAL_REQUEST, redisKey);
        }
        //获取分页数据
        ProdPageParams pageParams = new ProdPageParams();
        pageParams.setPage(params.getPage());
        pageParams.setSize(params.getSize());
        pageParams.setBuyerId(params.getBuyerId());
        pageParams.setPname(params.getPname());
        pageParams.setCid(params.getCid());
        PageBean<ProductDto> pageList = productService.getProdPageList(pageParams);
        if (pageList != null && pageList.getDataList() != null && pageList.getDataList().size() > 0) {
            List<StockProdDto> data = new ArrayList<>();
            Set<String> addedPids = redisTemplate.<String, String>opsForHash().keys(redisKey);
            pageList.getDataList().forEach(p -> {
                StockProdDto dto = new StockProdDto();
                dto.setPid(p.getPid());
                dto.setPnumber(p.getStockNumber());
                dto.setSnumber(BigDecimalUtil.getNumber(new BigDecimal("0"), 2));
                dto.setSubtotal(BigDecimalUtil.getNumber(new BigDecimal("0"), 2));
                dto.setPname(p.getPname());
                dto.setUnitName(p.getUnitName());
                dto.setPic(p.getPic());
                dto.setCostPrice(p.getCostPrice());
                dto.setFirstCname(p.getFirstCname());
                dto.setSecondCname(p.getSecondCname());
                dto.setThirdCname(p.getThirdCname());
                if (addedPids.contains(p.getPid())) {
                    dto.setGray(Boolean.TRUE);
                } else {
                    dto.setGray(Boolean.FALSE);
                }
                data.add(dto);
            });
            PageBean<StockProdDto> result = new PageBean<>(pageList.getPage(), pageList.getSize(), data, pageList.getTotal());
            return new ResponseResult<>(CodeStatus.OK, "查询成功", result);
        }
        return new ResponseResult<>(CodeStatus.OK, "查询成功", null);
    }

    @PreAuthorize("hasAnyAuthority('/','/stocking/get')")
    @PostMapping("/getAddedProd")
    @ApiOperation(value = "获取已添加的商品", notes = "必传参数：新增单据时status为0，传递当前登录用户userId;编辑单据时status为1，传递本单据id")
    public ResponseResult<List<StockProdDto>> getAddedProd(@Validated({CheckGroup.Get.class})
                                                           @RequestBody StockProdParams<StockProdDto> params) {
        String redisKey = getRedisKey(params);
        if (redisKey.startsWith("参数错误")) {
            return new ResponseResult<>(CodeStatus.ILLEGAL_REQUEST, redisKey);
        }
        List<StockProdDto> stockProdDtos = new ArrayList<>();
        List<String> values = redisTemplate.<String, String>opsForHash().values(redisKey);
        values.forEach(s -> {
            StockProdDto stockProdDto = JSON.parseObject(s, StockProdDto.class);
            stockProdDtos.add(stockProdDto);
        });
        return new ResponseResult<>(CodeStatus.OK, "查询成功", stockProdDtos);
    }

    @PreAuthorize("hasAnyAuthority('/','/stocking/manage')")
    @PostMapping("/addStockProd")
    @ApiOperation(value = "添加商品到出库购物车", notes = "新增单据时status为0，传递当前登录用户userId和添加的商品数组;编辑单据时status为1，传递本单据id和添加的商品数组；其他参数与此接口无关" +
            "另外，商品数组中每个商品的必要参数有pid，pnumber，snumber，subtotal，pname，unitName，pic，costPrice,firstCname，（secondCname，thirdCname有则传，无则不传）")
    public ResponseResult<Void> addOutstockProd(@Validated({CheckGroup.Add.class})
                                                @RequestBody StockProdParams<StockProdDto> params) {
        String redisKey = getRedisKey(params);
        if (redisKey.startsWith("参数错误")) {
            return new ResponseResult<>(CodeStatus.ILLEGAL_REQUEST, redisKey);
        }
        List<StockProdDto> prodList = params.getProdList();
        BoundHashOperations<String, String, String> ops = redisTemplate.<String, String>boundHashOps(redisKey);
        Map<String, String> map = new HashMap<>(prodList.size());
        prodList.forEach(p -> {
            p.setSnumber(BigDecimalUtil.formatTwoPoint(p.getSnumber()));
            p.setSubtotal(BigDecimalUtil.formatTwoPoint(p.getSubtotal()));
            map.put(p.getPid(), JSON.toJSONString(p));
        });
        if (map.size() > 0) {
            ops.putAll(map);
            ops.expire(1, TimeUnit.HOURS);
        }
        return new ResponseResult<>(CodeStatus.OK, "添加成功");
    }

    @PreAuthorize("hasAnyAuthority('/','/stocking/manage')")
    @PostMapping("/updateProd")
    @ApiOperation(value = "根据商品id修改出库购物车商品", notes = "必传参数：新增单据时status为0，传递当前登录用户userId和要修改的商品信息（pid，pnumber，snumber,subtotal）;编辑单据时status为1，传递本单据id和和要修改的商品信息（pid，pnumber，snumber,subtotal）")
    public ResponseResult<Void> updateProd(@Validated({CheckGroup.Update.class, CheckGroup.Stocking.class})
                                           @RequestBody StockProdParams<StockProdDto> params) {
        String redisKey = getRedisKey(params);
        if (redisKey.startsWith("参数错误")) {
            return new ResponseResult<>(CodeStatus.ILLEGAL_REQUEST, redisKey);
        }
        BoundHashOperations<String, String, String> ops = redisTemplate.<String, String>boundHashOps(redisKey);
        String json = ops.get(params.getPid());
        if (StringUtils.isBlank(json)) {
            return new ResponseResult<>(CodeStatus.FAIL, "修改失败，请刷新页面");
        }
        StockProdDto stockProdDto = JSON.parseObject(json, StockProdDto.class);
        stockProdDto.setSnumber(BigDecimalUtil.formatTwoPoint(new BigDecimal(params.getSnumber().toString())));
        stockProdDto.setSubtotal(BigDecimalUtil.formatTwoPoint(new BigDecimal(params.getSubtotal().toString())));
        ops.put(stockProdDto.getPid(), JSON.toJSONString(stockProdDto));
        return new ResponseResult<>(CodeStatus.OK, "修改成功");
    }

    @PreAuthorize("hasAnyAuthority('/','/stocking/manage')")
    @PostMapping("/deleteProd")
    @ApiOperation(value = "根据商品id删除出库购物车商品", notes = "必传参数：必传参数：新增单据时status为0，传递当前登录用户userId和要删除的商品pid;编辑单据时status为1，传递本单据id和要删除的商品pid")
    public ResponseResult<Void> deleteProd(@Validated({CheckGroup.Delete.class})
                                           @RequestBody StockProdParams<StockProdDto> params) {
        String redisKey = getRedisKey(params);
        if (redisKey.startsWith("参数错误")) {
            return new ResponseResult<>(CodeStatus.ILLEGAL_REQUEST, redisKey);
        }
        redisTemplate.opsForHash().delete(redisKey, params.getPid());
        return new ResponseResult<>(CodeStatus.OK, "删除成功");
    }

    @PreAuthorize("hasAnyAuthority('/','/stocking/manage')")
    @PostMapping("/deleteAll")
    @ApiOperation(value = "清空购物车", notes = "必传参数：新增单据时status为0，传递当前登录用户userId;编辑单据时status为1，传递本单据id")
    public ResponseResult<Void> deleteAll(@Validated({CheckGroup.Get.class})
                                          @RequestBody StockProdParams<StockProdDto> params) {
        String redisKey = getRedisKey(params);
        if (redisKey.startsWith("参数错误")) {
            return new ResponseResult<>(CodeStatus.ILLEGAL_REQUEST, redisKey);
        }
        redisTemplate.delete(redisKey);
        return new ResponseResult<>(CodeStatus.OK, "删除成功");
    }

    /**
     * 获取redisKey
     * 新增页面 key对应 用户id，编辑页面key对应 单据id
     *
     * @param params
     * @return
     */
    private String getRedisKey(StockProdParams<StockProdDto> params) {
        Object id = null;
        if (params.getStatus().equals(StockConstant.INSERT)) {
            if (params.getUserId() == null) {
                return "参数错误：新增页面请传递用户id";
            }
            id = params.getUserId();
        } else if (params.getStatus().equals(StockConstant.UPDATE)) {
            if (StringUtils.isBlank(params.getId())) {
                return "参数错误：编辑页面请传递单据id";
            }
            id = params.getId();
        }
        return RedisKeyConstant.STOCKING + id;
    }
}
